package ch.ams.fhnw.sudoku;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractCellEditor;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;

public class SudokuFrame extends JFrame implements ActionListener {

	private static final long serialVersionUID = 1L;
	
	private final static int GAP_WIDTH = 10;
	private final static int GAP_HEIGHT = 10;
	private final static int ROW_HEIGHT = 25;
	private final static int COLUMN_WIDTH = 25;
	
	private JTable table;
	private JButton solveButton;
	private JButton clearButton;
	
	public SudokuFrame() {
		Container contentPane = getContentPane();
		contentPane.setLayout(new BorderLayout());
		
		table = new JTable(new SudokuTableModel());
		
		//table selection
		table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
		table.setRowSelectionAllowed(false);
		table.setColumnSelectionAllowed(false);
		
		//set size of table
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		table.setIntercellSpacing( new Dimension(GAP_WIDTH, GAP_HEIGHT) );
		table.setRowHeight( ROW_HEIGHT + GAP_HEIGHT );
		int columnCount = table.getColumnModel().getColumnCount();
		for (int i = 0; i < columnCount; i++) {
			TableColumn column = table.getColumnModel().getColumn(i);
			column.setPreferredWidth(COLUMN_WIDTH + GAP_WIDTH);
			column.setCellEditor(new CenterTableCellEditor()); //add cell editor for each column
		}
		
		contentPane.add(table, BorderLayout.CENTER);
		
		//buttons
		solveButton = new JButton("Solve");
		solveButton.addActionListener(this);
		
		clearButton = new JButton("Clear");
		clearButton.addActionListener(this);
		
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
		buttonPanel.add(Box.createHorizontalGlue());
		buttonPanel.add(clearButton);
		buttonPanel.add(solveButton);
		contentPane.add(buttonPanel, BorderLayout.SOUTH);
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setResizable(false);
		setVisible(true);
		
		setExampleData();
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		
		if(e.getSource() == solveButton) {
			SudokuTableModel model = (SudokuTableModel) table.getModel();
			SudokuSolver3 solver = new SudokuSolver3(model.getSudokuData());
			
			System.out.println("\ntry to solve :");
			System.out.println(model.toString());
			
			if(!solver.validate()) {
				System.out.println("invalid sudoku data");
				return;
			}
			
			solver.solve();
			if(solver.hasSolution()) {
				String res = new SudokuTableModel(solver.getResult()).toString();
				System.out.println("\nSolution: ");
				System.out.println(res);
				System.out.println("Duration: " + solver.getSolveTime() + "ms");
				System.out.println("Iterations: " + solver.getIterations());
			} else {
				System.out.println("\nno solution found");
			}
			
		}
		
		if(e.getSource() == clearButton) {
			table.setModel(new SudokuTableModel());
		}
	}
	
	private class CenterTableCellEditor extends AbstractCellEditor implements TableCellEditor {
		
		private static final long serialVersionUID = 1L;
		
		private JTextField textField = new JTextField();
		
		public CenterTableCellEditor() {
			textField.setForeground(Color.red);
			textField.setAlignmentX(JTextField.CENTER);
		}

		@Override
		public Component getTableCellEditorComponent(JTable table,
				Object value, boolean isSelected, int rowIndex, int colIndex) {
			
			if(value == null) {
				textField.setText("");
			} else {
				textField.setText(value.toString());
			}
			return textField;
		}

		@Override
		public Object getCellEditorValue() {
			return textField.getText();
		}
	}
	
	
	public static void main(String[] args) throws ClassNotFoundException,
			InstantiationException, IllegalAccessException,
			UnsupportedLookAndFeelException {

		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

		new Thread(new Runnable() {

			@Override
			public void run() {
				new SudokuFrame();
			}
		}).start();
	}
	
	private void setExampleData() {
		//easy
		int[][] data = { 
				{ 0, 1, 2, 4, 5, 0, 0, 0, 0 },
				{ 0, 9, 0, 0, 6, 1, 0, 8, 0 }, 
				{ 6, 0, 0, 0, 2, 0, 0, 0, 0 },
				{ 0, 4, 0, 1, 0, 2, 5, 0, 0 }, 
				{ 0, 8, 5, 7, 0, 0, 3, 0, 0 },
				{ 0, 6, 0, 9, 0, 5, 0, 7, 8 }, 
				{ 1, 0, 0, 0, 0, 0, 2, 3, 4 },
				{ 3, 5, 8, 0, 0, 0, 0, 0, 6 }, 
				{ 4, 0, 0, 0, 0, 0, 0, 0, 0 } };
		
		//medium
		int[][] data2 = { 
				{ 0, 0, 1, 0, 0, 0, 0, 0, 9 },
				{ 0, 5, 0, 2, 0, 3, 1, 7, 0 }, 
				{ 9, 0, 0, 0, 0, 0, 0, 0, 5 },
				{ 0, 0, 0, 0, 0, 7, 6, 1, 8 }, 
				{ 0, 0, 0, 4, 0, 0, 0, 0, 0 },
				{ 7, 2, 0, 0, 0, 0, 0, 0, 3 }, 
				{ 0, 0, 7, 6, 0, 0, 4, 0, 0 },
				{ 0, 4, 0, 0, 8, 1, 0, 0, 2 }, 
				{ 0, 0, 0, 9, 0, 0, 7, 0, 0 } };
		
		//easy
		int[][] data3 = { 
				{ 1, 0, 0, 5, 0, 3, 0, 8, 9 },
				{ 0, 9, 0, 0, 7, 0, 2, 0, 0 }, 
				{ 6, 0, 0, 0, 0, 0, 0, 0, 3 },
				{ 4, 0, 0, 0, 8, 0, 1, 3, 0 }, 
				{ 0, 6, 7, 0, 3, 0, 4, 9, 0 },
				{ 0, 0, 1, 0, 4, 0, 0, 0, 8 }, 
				{ 9, 0, 0, 0, 0, 0, 0, 0, 6 },
				{ 0, 0, 4, 0, 1, 0, 0, 2, 0 }, 
				{ 7, 2, 0, 8, 0, 9, 0, 0, 1 } };
		
		//difficult
		int[][] data4 = { 
				{ 0, 0, 0, 8, 0, 0, 0, 3, 0 },
				{ 0, 5, 0, 0, 0, 0, 6, 0, 0 }, 
				{ 0, 0, 0, 4, 0, 0, 0, 0, 0 },
				{ 3, 0, 0, 0, 0, 0, 0, 7, 0 }, 
				{ 0, 0, 0, 0, 8, 0, 0, 4, 0 },
				{ 0, 1, 0, 0, 5, 0, 0, 0, 0 }, 
				{ 2, 0, 0, 0, 6, 0, 5, 0, 0 },
				{ 4, 0, 0, 7, 0, 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0, 0, 0, 1, 0, 0 } };
		
		table.setModel(new SudokuTableModel(data4));
	}
}
